/*
 * 	FIFO manager
 *
 * 	$Id: queue.h 11 2008-12-11 03:00:10Z ybc2084 $
 *
 */

#ifndef	_QUEUE_H_
#define	_QUEUE_H_

#ifdef	__cplusplus
extern "C" {
#endif

#include <pthread.h>
#include "type.h"

/*
 * upper bound of queue length, reserved
 */
extern const int MAX_LEN_OF_QUEUE;

/*
 * typedef queue elments.
 * QueueNode is opaque to client
 */
typedef	void *				QueueNodeData;
typedef struct _QueueNode	QueueNode;
typedef struct _Queue		Queue;


/*
 * QueueNode definition
 */
struct _QueueNode {

	/****************************
	 * private members
	 ****************************/

	/* mutex related, reserved for thread */
	pthread_mutexattr_t	muxattr;
	pthread_mutex_t		mux;

	/* data */
	QueueNodeData		data;

	/* point to previous and next node */
	QueueNode		   *prev;
	QueueNode		   *next;

	/* simulate constructor and destructor */
	void			(*init)(QueueNode *node);
	void			(*fini)(QueueNode *node);

	/****************************
	 * public members
	 ****************************/

	/* lock and unlock, now just placeholder */
	void			(*lock)(const QueueNode *node);
	void			(*unlock)(const QueueNode *node);

	/* maintenance function */
	QueueNode*		(*getPrevNode)(const QueueNode *node);
	QueueNode*		(*delPrevNode)(QueueNode *node);
	QueueNode*		(*insPrevNode)(QueueNode *node, QueueNode *prev);

	QueueNode*		(*getNextNode)(const QueueNode *node);
	QueueNode*		(*delNextNode)(QueueNode *node);
	QueueNode*		(*insNextNode)(QueueNode *node, QueueNode *next);

	QueueNodeData 	(*getData)(const QueueNode *node);
	QueueNodeData	(*setData)(QueueNode *node, 
							   const QueueNodeData const data);
};

/*
 * simulate new/del op on QueueNode
 */
extern QueueNode*	NewQueueNode(void);
extern void			DelQueueNode(QueueNode *node);


/*
 * Queue definition, based on double-linked list
 */
struct _Queue {

	/****************************
	 * private members
	 ****************************/

	/* queue head */
	QueueNode			*head;

	/* simulate queue constructor */
	void				(*init)(Queue *q);

	/* simulate queue destructor */
	void				(*fini)(Queue *q);

	/* head node of queue: as sentinel */
	QueueNode*			(*getHead)(const Queue *q);
	QueueNode*			(*setHead)(Queue *q, QueueNode * const head);

	/****************************
	 * public members
	 ****************************/

	/* dequeue */
	QueueNodeData		(*dequeue)(Queue *q);

	/* enqueue */
	QueueNodeData		(*enqueue)(Queue *q, const QueueNodeData data);

	/* is the queue empty? */
	bool				(*isEmpty)(const Queue *q);

	/* is the queue full? */
	bool				(*isFull)(const Queue *q);

	/*--------------------------------------------
	 * defaultly, when destroying a queue by invoking
	 * q->fini(), the data pointer contained in queue
	 * node won't be freed. this method provide client 
	 * another chance to make a different decision. 
	 * 'release' argument indicate whether release the
	 * data pointer. noteworthy, this method won't 
	 * release head node of queue.
	 * XXX: However, it seems not an elegant approach 
	 * here, it may need further consideration.
	 */
	void				(*purge)(Queue *q, bool release);
};

/*
 * simulate new/del op on Queue
 */
extern Queue*		NewQueue(void);
extern void			DelQueue(Queue *q);

#ifdef	__cplusplus
}
#endif

#endif	/* _QUEUE_H_ */

